import Chain from './chain';
import {
  AndOperator,
  CatchOperator,
  ForOperator,
  IfOperator,
  IteratorOperator,
  NodeOperator,
  NotOperator,
  OrOperator,
  SwitchOperator,
  ThenOperator,
  WhenOperator,
  WhileOperator,
  ChainOperator,
} from './el';
import { ConditionTypeEnum, NodeTypeEnum } from '../constant';
import ELNode from './node';

/**
 * 将EL表达式的JSON表示，构造成ELNode模型表示。
 * EL表达式的模型表示：数据结构本质上是一个树形结构。
 * 例如一个串行编排(THEN)：
 * (1) EL表达式形式：THEN(a, b, c, d)
 * (2) JSON表示形式：
 * {
    type: ConditionTypeEnum.THEN,
    children: [
      { type: NodeTypeEnum.COMMON, id: 'a' },
      { type: NodeTypeEnum.COMMON, id: 'b' },
      { type: NodeTypeEnum.COMMON, id: 'c' },
      { type: NodeTypeEnum.COMMON, id: 'd' },
    ],
  }
 */
export default class ELBuilder {
  static build(data) {
    return builder(data);
  }

  static createELNode(type, parent, id) {
    switch (type) {
      // 1. 编排类型
      case ConditionTypeEnum.THEN:
      case ConditionTypeEnum.SER:
        return ThenOperator.create(parent);
      case ConditionTypeEnum.WHEN:
      case ConditionTypeEnum.PAR:
        return WhenOperator.create(parent);
      case ConditionTypeEnum.SWITCH:
        return SwitchOperator.create(parent);
      case ConditionTypeEnum.IF:
        return IfOperator.create(parent);
      case ConditionTypeEnum.FOR:
        return ForOperator.create(parent);
      case ConditionTypeEnum.WHILE:
        return WhileOperator.create(parent);
      case ConditionTypeEnum.ITERATOR:
        return IteratorOperator.create(parent);
      case ConditionTypeEnum.CATCH:
        return CatchOperator.create(parent);
      case ConditionTypeEnum.AND:
        return AndOperator.create(parent);
      case ConditionTypeEnum.OR:
        return OrOperator.create(parent);
      case ConditionTypeEnum.NOT:
        return NotOperator.create(parent);
      case ConditionTypeEnum.CHAIN:
        return ChainOperator.create(parent);
      case ConditionTypeEnum.PRE:
      case ConditionTypeEnum.FINALLY:
      case ConditionTypeEnum.BREAK:
      case ConditionTypeEnum.ABSTRACT:
      case ConditionTypeEnum.DEFAULT:
        return ThenOperator.create(parent);
      // 2. 节点类型
      case NodeTypeEnum.COMMON:
      case NodeTypeEnum.BOOLEAN:
      case NodeTypeEnum.SWITCH:
      case NodeTypeEnum.IF:
      case NodeTypeEnum.FOR:
      case NodeTypeEnum.WHILE:
      case NodeTypeEnum.BREAK:
      case NodeTypeEnum.ITERATOR:
      case NodeTypeEnum.SCRIPT:
      case NodeTypeEnum.BOOLEAN_SCRIPT:
      case NodeTypeEnum.SWITCH_SCRIPT:
      case NodeTypeEnum.IF_SCRIPT:
      case NodeTypeEnum.FOR_SCRIPT:
      case NodeTypeEnum.WHILE_SCRIPT:
      case NodeTypeEnum.BREAK_SCRIPT:
      case NodeTypeEnum.FALLBACK:
      case NodeTypeEnum.VIRTUAL:
        return NodeOperator.create(parent, id);
      default:
        return NodeOperator.create(parent, id);
    }
  }
}

export function builder(data) {
  if (!data) {
    return Chain.create();
  }

  if (Array.isArray(data)) {
    return Chain.create(data);
  }

  return parse({ parent: null, data });
}

export function parse({ parent, data }) {
  if (!data) {
    return undefined;
  }

  const { type, children, condition, id, properties, collapsed } = data;

  if (!type) {
    return undefined;
  }

  const node = parseOperator({ parent, data, type });

  if (properties) {
    node.setProperties(properties);
  }

  if (collapsed !== undefined) {
    node.toggleCollapse(collapsed);
  }

  if (condition) {
    const conditionNode = parse({ parent: node, data: condition });
    if (conditionNode) {
      node.condition = conditionNode;
    }
  }

  if (children && Array.isArray(children)) {
    children.forEach(childData => {
      const childNode = parse({ parent: node, data: childData });
      if (childNode) {
        node.appendChild(childNode);
      }
    });
  }

  return node;
}

function parseOperator({ parent, data, type }) {
  const { id } = data;
  return ELBuilder.createELNode(type, parent, id);
} 